package com.ruoyi.module.controller;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.module.domain.UserWordRecord;
import com.ruoyi.module.domain.UserChapterRecord;
import com.ruoyi.module.domain.UserEvalRecord;
import com.ruoyi.module.service.IUserWordRecordService;
import com.ruoyi.module.service.IUserChapterRecordService;
import com.ruoyi.module.service.IUserEvalRecordService;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * 数据统计分析Controller
 * 
 * @author ruoyi
 */
@RestController
@RequestMapping("/analytics")
public class AnalyticsController extends BaseController
{
    @Autowired
    private IUserWordRecordService userWordRecordService;

    @Autowired
    private IUserChapterRecordService userChapterRecordService;

    @Autowired
    private IUserEvalRecordService userEvalRecordService;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 获取练习热力图数据
     */
    @GetMapping("/heatmap")
    public AjaxResult getHeatmapData(
        @RequestParam Long startTime,
        @RequestParam Long endTime,
        @RequestParam String type)
    {
        try {
            UserChapterRecord query = new UserChapterRecord();
            query.setUserId(SecurityUtils.getUserId());
            query.getParams().put("beginTimestamp", startTime);
            query.getParams().put("endTimestamp", endTime);
            
            List<UserChapterRecord> records = userChapterRecordService.selectUserChapterRecordList(query);
            
            Map<String, Integer> heatmapData = new HashMap<>();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            
            for (UserChapterRecord record : records) {
                // 将时间戳转为日期
                LocalDate date = Instant.ofEpochMilli(record.getTimestamp())
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
                String dateStr = date.format(formatter);
                
                if ("exercise".equals(type)) {
                    // 练习次数
                    heatmapData.put(dateStr, heatmapData.getOrDefault(dateStr, 0) + 1);
                } else if ("word".equals(type)) {
                    // 单词数
                    int wordCount = record.getWordCount() != null ? record.getWordCount() : 0;
                    heatmapData.put(dateStr, heatmapData.getOrDefault(dateStr, 0) + wordCount);
                }
            }
            
            return AjaxResult.success(heatmapData);
        } catch (Exception e) {
            logger.error("获取热力图数据失败", e);
            return AjaxResult.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 获取WPM趋势数据
     */
    @GetMapping("/wpm-trend")
    public AjaxResult getWpmTrend(
        @RequestParam Long startTime,
        @RequestParam Long endTime,
        @RequestParam(required = false) String dictId)
    {
        try {
            UserChapterRecord query = new UserChapterRecord();
            query.setUserId(SecurityUtils.getUserId());
            query.getParams().put("beginTimestamp", startTime);
            query.getParams().put("endTimestamp", endTime);
            if (dictId != null && !dictId.isEmpty()) {
                query.setDictId(dictId);
            }
            
            List<UserChapterRecord> records = userChapterRecordService.selectUserChapterRecordList(query);
            
            // 按日期分组计算平均WPM
            Map<String, List<Integer>> dateWpmMap = new HashMap<>();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            
            for (UserChapterRecord record : records) {
                if (record.getWpm() != null && record.getWpm() > 0) {
                    LocalDate date = Instant.ofEpochMilli(record.getTimestamp())
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();
                    String dateStr = date.format(formatter);
                    
                    dateWpmMap.computeIfAbsent(dateStr, k -> new java.util.ArrayList<>()).add(record.getWpm());
                }
            }
            
            // 计算每天的统计数据
            List<Map<String, Object>> trendData = new java.util.ArrayList<>();
            for (Map.Entry<String, List<Integer>> entry : dateWpmMap.entrySet()) {
                List<Integer> wpms = entry.getValue();
                Map<String, Object> item = new HashMap<>();
                item.put("date", entry.getKey());
                item.put("avgWpm", wpms.stream().mapToInt(Integer::intValue).average().orElse(0));
                item.put("maxWpm", wpms.stream().mapToInt(Integer::intValue).max().orElse(0));
                item.put("minWpm", wpms.stream().mapToInt(Integer::intValue).min().orElse(0));
                trendData.add(item);
            }
            
            // 按日期排序
            trendData.sort((a, b) -> ((String) a.get("date")).compareTo((String) b.get("date")));
            
            return AjaxResult.success(trendData);
        } catch (Exception e) {
            logger.error("获取WPM趋势失败", e);
            return AjaxResult.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 获取正确率趋势数据
     */
    @GetMapping("/accuracy-trend")
    public AjaxResult getAccuracyTrend(
        @RequestParam Long startTime,
        @RequestParam Long endTime,
        @RequestParam(required = false) String dictId)
    {
        try {
            UserChapterRecord query = new UserChapterRecord();
            query.setUserId(SecurityUtils.getUserId());
            query.getParams().put("beginTimestamp", startTime);
            query.getParams().put("endTimestamp", endTime);
            if (dictId != null && !dictId.isEmpty()) {
                query.setDictId(dictId);
            }
            
            List<UserChapterRecord> records = userChapterRecordService.selectUserChapterRecordList(query);
            
            // 按日期分组计算平均正确率
            Map<String, List<Integer>> dateAccuracyMap = new HashMap<>();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            
            for (UserChapterRecord record : records) {
                if (record.getInputAccuracy() != null && record.getInputAccuracy() > 0) {
                    LocalDate date = Instant.ofEpochMilli(record.getTimestamp())
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();
                    String dateStr = date.format(formatter);
                    
                    dateAccuracyMap.computeIfAbsent(dateStr, k -> new java.util.ArrayList<>()).add(record.getInputAccuracy());
                }
            }
            
            // 计算每天的平均正确率
            List<Map<String, Object>> trendData = new java.util.ArrayList<>();
            for (Map.Entry<String, List<Integer>> entry : dateAccuracyMap.entrySet()) {
                List<Integer> accuracies = entry.getValue();
                Map<String, Object> item = new HashMap<>();
                item.put("date", entry.getKey());
                item.put("avgAccuracy", accuracies.stream().mapToInt(Integer::intValue).average().orElse(0));
                trendData.add(item);
            }
            
            // 按日期排序
            trendData.sort((a, b) -> ((String) a.get("date")).compareTo((String) b.get("date")));
            
            return AjaxResult.success(trendData);
        } catch (Exception e) {
            logger.error("获取正确率趋势失败", e);
            return AjaxResult.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 获取按键错误统计
     */
    @GetMapping("/key-errors")
    public AjaxResult getKeyErrors(
        @RequestParam Long startTime,
        @RequestParam Long endTime)
    {
        try {
            UserWordRecord query = new UserWordRecord();
            query.setUserId(SecurityUtils.getUserId());
            query.getParams().put("beginTimestamp", startTime);
            query.getParams().put("endTimestamp", endTime);
            
            List<UserWordRecord> records = userWordRecordService.selectUserWordRecordList(query);
            
            Map<String, Integer> keyErrorMap = new HashMap<>();
            
            // 解析每个记录的mistakes字段，统计按键错误
            for (UserWordRecord record : records) {
                if (record.getMistakes() != null && !record.getMistakes().isEmpty() && !"{}".equals(record.getMistakes())) {
                    try {
                        Map<String, List<String>> mistakes = objectMapper.readValue(
                            record.getMistakes(), 
                            new com.fasterxml.jackson.core.type.TypeReference<Map<String, List<String>>>(){}
                        );
                        
                        for (Map.Entry<String, List<String>> entry : mistakes.entrySet()) {
                            List<String> errorKeys = entry.getValue();
                            for (String key : errorKeys) {
                                keyErrorMap.put(key, keyErrorMap.getOrDefault(key, 0) + 1);
                            }
                        }
                    } catch (Exception e) {
                        // 忽略JSON解析错误
                        logger.debug("解析mistakes字段失败: " + record.getMistakes(), e);
                    }
                }
            }
            
            return AjaxResult.success(keyErrorMap);
        } catch (Exception e) {
            logger.error("获取按键错误统计失败", e);
            return AjaxResult.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户总体统计
     */
    @GetMapping("/summary")
    public AjaxResult getUserSummary()
    {
        try {
            Long userId = SecurityUtils.getUserId();
            
            // 查询所有章节记录
            UserChapterRecord chapterQuery = new UserChapterRecord();
            chapterQuery.setUserId(userId);
            List<UserChapterRecord> chapterRecords = userChapterRecordService.selectUserChapterRecordList(chapterQuery);
            
            // 查询所有单词记录
            UserWordRecord wordQuery = new UserWordRecord();
            wordQuery.setUserId(userId);
            List<UserWordRecord> wordRecords = userWordRecordService.selectUserWordRecordList(wordQuery);
            
            Map<String, Object> summary = new HashMap<>();
            
            // 总练习次数
            summary.put("totalExerciseCount", chapterRecords.size());
            
            // 总单词数
            int totalWordCount = chapterRecords.stream()
                .mapToInt(r -> r.getWordCount() != null ? r.getWordCount() : 0)
                .sum();
            summary.put("totalWordCount", totalWordCount);
            
            // 总用时（秒）
            int totalTime = chapterRecords.stream()
                .mapToInt(r -> r.getTime() != null ? r.getTime() : 0)
                .sum();
            summary.put("totalTime", totalTime);
            
            // 平均WPM
            double avgWpm = chapterRecords.stream()
                .filter(r -> r.getWpm() != null && r.getWpm() > 0)
                .mapToInt(UserChapterRecord::getWpm)
                .average()
                .orElse(0);
            summary.put("avgWpm", (int) Math.round(avgWpm));
            
            // 平均正确率
            double avgAccuracy = chapterRecords.stream()
                .filter(r -> r.getInputAccuracy() != null && r.getInputAccuracy() > 0)
                .mapToInt(UserChapterRecord::getInputAccuracy)
                .average()
                .orElse(0);
            summary.put("avgAccuracy", (int) Math.round(avgAccuracy));
            
            // 学习词典数
            long totalDicts = chapterRecords.stream()
                .map(UserChapterRecord::getDictId)
                .distinct()
                .count();
            summary.put("totalDicts", totalDicts);
            
            // 完成章节数（排除复习记录）
            long completedChapters = chapterRecords.stream()
                .filter(r -> r.getChapter() != null && r.getChapter() >= 0)
                .map(r -> r.getDictId() + "_" + r.getChapter())
                .distinct()
                .count();
            summary.put("completedChapters", completedChapters);
            
            // 错词数量
            long errorWordCount = wordRecords.stream()
                .filter(r -> r.getWrongCount() != null && r.getWrongCount() > 0)
                .map(UserWordRecord::getWord)
                .distinct()
                .count();
            summary.put("errorWordCount", errorWordCount);
            
            // 学习天数
            long studyDays = chapterRecords.stream()
                .map(r -> {
                    LocalDate date = Instant.ofEpochMilli(r.getTimestamp())
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();
                    return date.toString();
                })
                .distinct()
                .count();
            summary.put("studyDays", studyDays);
            
            // 计算连续学习天数
            List<LocalDate> studyDates = chapterRecords.stream()
                .map(r -> Instant.ofEpochMilli(r.getTimestamp())
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate())
                .distinct()
                .sorted()
                .collect(Collectors.toList());
            
            int longestStreak = 0;
            int currentStreak = 0;
            
            if (!studyDates.isEmpty()) {
                int tempStreak = 1;
                LocalDate today = LocalDate.now();
                
                // 计算最长连续天数
                for (int i = 1; i < studyDates.size(); i++) {
                    if (studyDates.get(i).minusDays(1).equals(studyDates.get(i - 1))) {
                        tempStreak++;
                    } else {
                        longestStreak = Math.max(longestStreak, tempStreak);
                        tempStreak = 1;
                    }
                }
                longestStreak = Math.max(longestStreak, tempStreak);
                
                // 计算当前连续天数
                LocalDate lastStudyDate = studyDates.get(studyDates.size() - 1);
                if (lastStudyDate.equals(today) || lastStudyDate.equals(today.minusDays(1))) {
                    currentStreak = 1;
                    for (int i = studyDates.size() - 2; i >= 0; i--) {
                        if (studyDates.get(i + 1).minusDays(1).equals(studyDates.get(i))) {
                            currentStreak++;
                        } else {
                            break;
                        }
                    }
                }
            }
            
            summary.put("longestStreak", longestStreak);
            summary.put("currentStreak", currentStreak);
            
            // 查询评测数据
            UserEvalRecord evalQuery = new UserEvalRecord();
            evalQuery.setUserId(userId);
            List<UserEvalRecord> evalRecords = userEvalRecordService.selectUserEvalRecordList(evalQuery);
            
            // 总评测次数（按UUID去重）
            long totalEvalCount = evalRecords.stream()
                .map(UserEvalRecord::getUuid)
                .distinct()
                .count();
            summary.put("totalEvalCount", totalEvalCount);
            
            // 评测平均分
            double avgEvalScore = evalRecords.stream()
                .filter(r -> r.getScore() != null && r.getScore() > 0)
                .mapToInt(UserEvalRecord::getScore)
                .average()
                .orElse(0);
            summary.put("avgEvalScore", (int) Math.round(avgEvalScore));
            
            // 评测单词总数
            summary.put("totalEvalWords", evalRecords.size());
            
            return AjaxResult.success(summary);
        } catch (Exception e) {
            logger.error("获取用户总体统计失败", e);
            return AjaxResult.error("查询失败: " + e.getMessage());
        }
    }

    /**
     * 获取评测统计数据
     */
    @GetMapping("/eval-stats")
    public AjaxResult getEvalStats(
        @RequestParam Long startTime,
        @RequestParam Long endTime,
        @RequestParam(required = false) String dictId)
    {
        try {
            UserEvalRecord query = new UserEvalRecord();
            query.setUserId(SecurityUtils.getUserId());
            query.getParams().put("beginTimestamp", startTime);
            query.getParams().put("endTimestamp", endTime);
            if (dictId != null && !dictId.isEmpty()) {
                query.setDictId(dictId);
            }
            
            List<UserEvalRecord> records = userEvalRecordService.selectUserEvalRecordList(query);
            
            Map<String, Object> stats = new HashMap<>();
            
            // 总评测次数（按UUID去重）
            long totalEvalSessions = records.stream()
                .map(UserEvalRecord::getUuid)
                .distinct()
                .count();
            stats.put("totalEvalSessions", totalEvalSessions);
            
            // 评测单词总数
            stats.put("totalWords", records.size());
            
            // 平均分数
            double avgScore = records.stream()
                .filter(r -> r.getScore() != null && r.getScore() > 0)
                .mapToInt(UserEvalRecord::getScore)
                .average()
                .orElse(0);
            stats.put("avgScore", Math.round(avgScore));
            
            // 分数分布
            long excellentCount = records.stream().filter(r -> r.getScore() != null && r.getScore() >= 90).count();
            long goodCount = records.stream().filter(r -> r.getScore() != null && r.getScore() >= 60 && r.getScore() < 90).count();
            long poorCount = records.stream().filter(r -> r.getScore() != null && r.getScore() < 60).count();
            
            Map<String, Long> distribution = new HashMap<>();
            distribution.put("excellent", excellentCount);
            distribution.put("good", goodCount);
            distribution.put("poor", poorCount);
            stats.put("distribution", distribution);
            
            // 按日期分组的评测趋势
            Map<String, List<Integer>> dateScoreMap = new HashMap<>();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            
            for (UserEvalRecord record : records) {
                if (record.getScore() != null && record.getScore() > 0) {
                    LocalDate date = Instant.ofEpochMilli(record.getTimestamp())
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();
                    String dateStr = date.format(formatter);
                    
                    dateScoreMap.computeIfAbsent(dateStr, k -> new java.util.ArrayList<>()).add(record.getScore());
                }
            }
            
            // 计算每天的平均分
            List<Map<String, Object>> trendData = new java.util.ArrayList<>();
            for (Map.Entry<String, List<Integer>> entry : dateScoreMap.entrySet()) {
                List<Integer> scores = entry.getValue();
                Map<String, Object> item = new HashMap<>();
                item.put("date", entry.getKey());
                item.put("avgScore", scores.stream().mapToInt(Integer::intValue).average().orElse(0));
                trendData.add(item);
            }
            
            // 按日期排序
            trendData.sort((a, b) -> ((String) a.get("date")).compareTo((String) b.get("date")));
            stats.put("trend", trendData);
            
            return AjaxResult.success(stats);
        } catch (Exception e) {
            logger.error("获取评测统计失败", e);
            return AjaxResult.error("查询失败: " + e.getMessage());
        }
    }
}


